Initial implementation of reprocessing xia2.multiplex jobs via SynchWeb - #384
Initial implementation of reprocessing xia2.multiplex jobs via SynchWeb#384amyjaynethompson wants to merge 7 commits into
Conversation
| cchalf_filtering_method: Optional[str] = None | ||
| sd_cutoff: Optional[float] = None | ||
| image_group_size: Optional[int] = None | ||
| scaling_id: Optional[int] = None |
There was a problem hiding this comment.
scaling_id should be a required parameter as reprocessing will not work without it
There was a problem hiding this comment.
Very true - have removed Optional
| # First, use the input scaling ID to find the DCIDs of all multiplex jobs as well as the sample (group) id value | ||
|
|
||
| query = ( | ||
| session.query(ProcessingJobImageSweep, ProcessingJobParameter) | ||
| .join( | ||
| AutoProcProgram, | ||
| AutoProcProgram.processingJobId | ||
| == ProcessingJobImageSweep.processingJobId, | ||
| ) | ||
| .join( | ||
| ProcessingJobParameter, | ||
| ProcessingJobParameter.processingJobId | ||
| == AutoProcProgram.processingJobId, | ||
| ) | ||
| .join( | ||
| AutoProc, | ||
| AutoProc.autoProcProgramId == AutoProcProgram.autoProcProgramId, | ||
| ) | ||
| .join(AutoProcScaling, AutoProcScaling.autoProcId == AutoProc.autoProcId) | ||
| .where(AutoProcScaling.autoProcScalingId == parameters.scaling_id) | ||
| .options( | ||
| Load(ProcessingJobImageSweep).load_only( | ||
| ProcessingJobImageSweep.dataCollectionId, | ||
| raiseload=True, | ||
| ), | ||
| Load(ProcessingJobParameter).load_only( | ||
| ProcessingJobParameter.parameterKey, | ||
| ProcessingJobParameter.parameterValue, | ||
| raiseload=True, | ||
| ), | ||
| ) | ||
| ) | ||
|
|
||
| return {"success": True, "return_value": jobids} | ||
| found_dcids = set() | ||
| group = None | ||
| found_data_files = set() | ||
|
|
||
| for dc, dc_params in query.all(): | ||
| found_dcids.add(dc.dataCollectionId) | ||
| if "sample_id" == dc_params.parameterKey: | ||
| group = ("sample_id", dc_params.parameterValue) | ||
| elif "sample_group_id" == dc_params.parameterKey: | ||
| group = ("sample_group_id", dc_params.parameterValue) | ||
| elif "data" == dc_params.parameterKey: | ||
| found_data_files.add(dc_params.parameterValue) | ||
|
|
||
| # Set parameters | ||
|
|
||
| dcids = list(found_dcids) | ||
| data_files = list(found_data_files) | ||
|
|
||
| self.log.info(f"Found {dcids} corresponding to {group}") | ||
|
|
||
| self.log.debug(f"Found data files {data_files}") | ||
|
|
||
| job_parameters: list[tuple[str, str]] = [ | ||
| ("data", files) for files in data_files | ||
| ] | ||
| if group: | ||
| job_parameters.append(group) | ||
|
|
There was a problem hiding this comment.
This could be simplified a lot by splitting into two queries. The issue with the single query is that you effectively get a duplicate of the processingJobParameters for each dcid. If you split it into two queries, the handling of the parameters becomes much easier.
| # First, use the input scaling ID to find the DCIDs of all multiplex jobs as well as the sample (group) id value | |
| query = ( | |
| session.query(ProcessingJobImageSweep, ProcessingJobParameter) | |
| .join( | |
| AutoProcProgram, | |
| AutoProcProgram.processingJobId | |
| == ProcessingJobImageSweep.processingJobId, | |
| ) | |
| .join( | |
| ProcessingJobParameter, | |
| ProcessingJobParameter.processingJobId | |
| == AutoProcProgram.processingJobId, | |
| ) | |
| .join( | |
| AutoProc, | |
| AutoProc.autoProcProgramId == AutoProcProgram.autoProcProgramId, | |
| ) | |
| .join(AutoProcScaling, AutoProcScaling.autoProcId == AutoProc.autoProcId) | |
| .where(AutoProcScaling.autoProcScalingId == parameters.scaling_id) | |
| .options( | |
| Load(ProcessingJobImageSweep).load_only( | |
| ProcessingJobImageSweep.dataCollectionId, | |
| raiseload=True, | |
| ), | |
| Load(ProcessingJobParameter).load_only( | |
| ProcessingJobParameter.parameterKey, | |
| ProcessingJobParameter.parameterValue, | |
| raiseload=True, | |
| ), | |
| ) | |
| ) | |
| return {"success": True, "return_value": jobids} | |
| found_dcids = set() | |
| group = None | |
| found_data_files = set() | |
| for dc, dc_params in query.all(): | |
| found_dcids.add(dc.dataCollectionId) | |
| if "sample_id" == dc_params.parameterKey: | |
| group = ("sample_id", dc_params.parameterValue) | |
| elif "sample_group_id" == dc_params.parameterKey: | |
| group = ("sample_group_id", dc_params.parameterValue) | |
| elif "data" == dc_params.parameterKey: | |
| found_data_files.add(dc_params.parameterValue) | |
| # Set parameters | |
| dcids = list(found_dcids) | |
| data_files = list(found_data_files) | |
| self.log.info(f"Found {dcids} corresponding to {group}") | |
| self.log.debug(f"Found data files {data_files}") | |
| job_parameters: list[tuple[str, str]] = [ | |
| ("data", files) for files in data_files | |
| ] | |
| if group: | |
| job_parameters.append(group) | |
| # Get the job parameters from the existing multiplex job. | |
| job_parameters: list[tuple[str, str]] = ( | |
| session.query(ProcessingJobParameter.parameterKey, ProcessingJobParameter.parameterValue) | |
| .select_from(AutoProcProgram) | |
| .join( | |
| ProcessingJobParameter, | |
| ProcessingJobParameter.processingJobId | |
| == AutoProcProgram.processingJobId, | |
| ) | |
| .join( | |
| AutoProc, | |
| AutoProc.autoProcProgramId == AutoProcProgram.autoProcProgramId, | |
| ) | |
| .join(AutoProcScaling, AutoProcScaling.autoProcId == AutoProc.autoProcId) | |
| .where(AutoProcScaling.autoProcScalingId == parameters.scaling_id) | |
| ).all() | |
| # Get the dataCollectionIds used in the existing multiplex job | |
| parent_job_dcids: list[tuple[int]] = ( | |
| session.query(ProcessingJobImageSweep.dataCollectionId) | |
| .join( | |
| AutoProcProgram, | |
| AutoProcProgram.processingJobId | |
| == ProcessingJobImageSweep.processingJobId, | |
| ) | |
| .join( | |
| ProcessingJobParameter, | |
| ProcessingJobParameter.processingJobId | |
| == AutoProcProgram.processingJobId, | |
| ) | |
| .join( | |
| AutoProc, | |
| AutoProc.autoProcProgramId == AutoProcProgram.autoProcProgramId, | |
| ) | |
| .join(AutoProcScaling, AutoProcScaling.autoProcId == AutoProc.autoProcId) | |
| .where(AutoProcScaling.autoProcScalingId == parameters.scaling_id) | |
| ).all() | |
| dcids: list[int] = [row[0] for row in parent_job_dcids] |
There was a problem hiding this comment.
GitHub was grumpy about just applying this suggestion, but have now split the queries into two :)
| if parameters.spacegroup: | ||
| job_parameters.append(("spacegroup", parameters.spacegroup)) | ||
|
|
||
| if parameters.d_min: | ||
| job_parameters.append(("d_min", str(parameters.d_min))) | ||
|
|
||
| if ( | ||
| parameters.diffraction_plan_info | ||
| and parameters.diffraction_plan_info.anomalousScatterer | ||
| ): | ||
| job_parameters.extend( | ||
| [ | ||
| ("anomalous", "true"), | ||
| ("absorption_level", "high"), | ||
| ] | ||
| ) | ||
| if output_clusters: | ||
| job_parameters.extend( | ||
| [ | ||
| ("clustering.method", "coordinate"), | ||
| ("clustering.output_clusters", "true"), | ||
| ] | ||
| ) | ||
|
|
||
| # Unlike regular multiplex, filtering allowed regardless of beamline | ||
|
|
||
| if parameters.apply_cchalf_filtering: | ||
| job_parameters.append(("filtering.method", "deltacchalf")) | ||
| if parameters.cchalf_filtering_method: | ||
| job_parameters.append( | ||
| ("deltacchalf.mode", parameters.cchalf_filtering_method) | ||
| ) | ||
| if parameters.image_group_size: | ||
| job_parameters.append( | ||
| ("deltacchalf.group_size", str(parameters.image_group_size)) | ||
| ) | ||
| if parameters.sd_cutoff: | ||
| job_parameters.append( | ||
| ("deltacchalf.stdcutoff", str(parameters.sd_cutoff)) | ||
| ) |
There was a problem hiding this comment.
Some of this code, to append new parameters to the job parameters feels quite repetitive. It's not a huge issue but, particularly for the more simple additions, you could try doing this inside a loop to avoid having multiple if statements.
There was a problem hiding this comment.
Have put this into a loop - for simplicity in the loop I've kept the parameter name and then edited the wrappers to use the proper Phil parameter (using same idea as space group and d_min)
|
Tidied up code - local tests seem to work - to be merged and tested more during next shutdown once SynchWeb changes also merged. |
This PR provides an initial implementation to reprocess xia2.multiplex jobs. In a first instance, it might make sense to limit this feature to reprocessing existing jobs with different command line parameters. This is to keep the bookkeeping in SynchWeb as clear as possible.
This PR introduces a separate trigger function, because much of the main multiplex trigger function is unnecessary for a reprocessing job under this specification.
Examples of features of main trigger functions that don't work in this context:
Instead, an ISPyB query can get the information required based on the parent job.
In SynchWeb, the new job is assigned a new processingJobId in ISPyB, and user defined parameters are given processingJobParameterIds. One of the processingJobParameters is the autoProcScalingId of the original multiplex job. From here, it is straightforward to query the database to find the DCIDs contained in the original job (as well as which sample group, and the data paths included).
This has been tested using ispyb-dev-1 which now has a multiplex reprocessing button. Using this interface submits the parameters to the ISPyB database. A new multiplex recipe is then called with
zocalo.go -n -r trigger-multiplex -s ispyb_process=<processingJobId>where the processingJobId is the new job registered by SynchWeb (and linked to the user defined parameters).